﻿using FySystem.Data.OrmA.Attributes;
using FySystem.Data.OrmA.Formatter;
using FySystem.Data.OrmA.Reflection;
using System;
using System.Data.Common;

namespace FySystem.Data.OrmA.Db
{
    class DbProcess
    {
        /// <summary>
        /// 数据写入流程
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sqlFormatter"></param>
        /// <param name="dbProviderFactory"></param>
        /// <param name="reflectionInfo"></param>
        /// <param name="model"></param>
        /// <param name="isReturn"></param>
        /// <returns></returns>
        internal static T SaveModel<T>(ISqlFormatter sqlFormatter, DbProviderFactory dbProviderFactory, ReflectionInfo reflectionInfo, DBHelper dbHelper, T model, bool isReturn)
        {
            try
            {
                if (model == null)
                    throw new Exception("传入数据为空~");
                if (reflectionInfo.Table == null)
                    throw new Exception("不是Model类，不支持Save方法~");
                if (reflectionInfo.PrimaryKey == null)
                    throw new Exception("Model类无主键，不支持Save方法~");

                FyPrimaryKeyAttribute primaryAttr = (FyPrimaryKeyAttribute)reflectionInfo.PrimaryKey.Column;
                if (primaryAttr.PrimaryKeyType == PrimaryKeyTypes.Sequence && string.IsNullOrWhiteSpace(primaryAttr.Sequence))
                    throw new Exception("主键Sequence未定义~");

                object pkValue = null;                          //主键的值
                if (isReturn)
                {
                    /**如果需要返回主键，不同的数据库处理方式不同，有的需要先查出主键，然后将主键拼出SQL后写入数据库；
                     * 有的需要先插入数据，然后再查询最后插入的主键；还有的存入数据库的同时会返回主键；
                     * 所以假设所有的数据库都需要三步，只不过某些步骤可能会返回空值，只有当返回的是非空值时，才执行对应的操作
                     * */
                    //第一步查询主键
                    string preSQL = sqlFormatter.GetPrePKSQL(primaryAttr);

                    if (!string.IsNullOrWhiteSpace(preSQL))
                        pkValue = dbHelper.ExecuteScalar(dbProviderFactory, preSQL);        //先查出主键

                    //第二步，创建插入SQL
                    string midSQL = sqlFormatter.GetMidPKSQL(primaryAttr);
                    FormatResult fmtSave = BaseFormatter.CreateSaveSQL(sqlFormatter, dbProviderFactory, reflectionInfo, model, midSQL, ref pkValue, true);
                    if (string.IsNullOrWhiteSpace(midSQL))
                        dbHelper.ExecuteNonQuery(dbProviderFactory, fmtSave.Sql, fmtSave.Parameters);
                    else
                        pkValue = dbHelper.ExecuteScalar(dbProviderFactory, fmtSave.Sql, fmtSave.Parameters);

                    //第三步，执行后置主键查询
                    if (string.IsNullOrWhiteSpace(midSQL) && pkValue == null)
                    {
                        string postSQL = sqlFormatter.GetPostPKSQL(primaryAttr);
                        if (!string.IsNullOrWhiteSpace(postSQL))
                            pkValue = dbHelper.ExecuteScalar(dbProviderFactory, postSQL);
                    }

                    //将主键值赋值给模型
                    DataCopy.SetPropertyValue(model, reflectionInfo.PrimaryKey.PropertyInfo, pkValue);
                }
                else
                {
                    //如果不需要返回主键
                    FormatResult fmtSave = BaseFormatter.CreateSaveSQL(sqlFormatter, dbProviderFactory, reflectionInfo, model, string.Empty, ref pkValue, false);
                    dbHelper.ExecuteNonQuery(dbProviderFactory, fmtSave.Sql, fmtSave.Parameters);
                }
            }
            catch (Exception)
            {
                throw;
            }
            return model;
        }
    }
}
